﻿#include "PageCache.h"
#include "Common.h"

// 初始化PageCache
PageCache PageCache::_sInst;

Span* PageCache::MapObjectToSpan(void* obj)
{
	PAGE_ID id = (PAGE_ID)obj >> PAGE_SHIFT;

	Span* result = static_cast<Span*>(_idSpanMap.Get(id));
	if (result != nullptr)
	{
		return result;
	}
	else
	{
		assert(false);
		return nullptr;
	}

	/*std::unique_lock<std::mutex> lock(_pMutex);
	std::map<PAGE_ID, Span*>::iterator it = _idSpanMap.find(id);
	if (it != _idSpanMap.end())
	{
		return it->second;
	}
	else
	{
		assert(false);
		return nullptr;
	}*/
}

void PageCache::ReleaseSpanToPageCache(Span* span)
{
	// 大于128页的直接归还给堆
	if (span->_pageNum > static_cast<size_t>(NPAGES) - 1)
	{
		void* ptr = (void*)(span->_pageId << PAGE_SHIFT);
		SystemFree(ptr);
		// delete span;
		_spanPool.Delete(span);
		return;
	}

	// 合并span前后的页，缓解内存碎片
	while (true)
	{
		PAGE_ID prevId = span->_pageId - 1;
		Span* prevSpan = static_cast<Span*>(_idSpanMap.Get(prevId));
		if (prevSpan == nullptr)
		{
			break;
		}

		//std::map<PAGE_ID, Span*>::iterator it = _idSpanMap.find(prevId);
		//// 如果没有找到前面的页，直接退出
		//if (it == _idSpanMap.end())
		//{
		//	break;
		//}
		//Span* prevSpan = it->second;

		//如果前面的span正在使用，那么就不可以合并
		if (prevSpan->_isUse == true)
		{
			break;
		}

		// 如果找到了，但是加起来超过了128页（没办法管理）
		if (prevSpan->_pageNum + span->_pageNum > static_cast<size_t>(NPAGES) - 1)
		{
			break;
		}

		// 找到了没有被使用而且还不超过128页
		// 开始合并
		span->_pageId = prevSpan->_pageId;
		span->_pageNum += prevSpan->_pageNum;

		_spanLists[span->_pageNum].Erase(prevSpan);
		// delete prevSpan;
		_spanPool.Delete(prevSpan);
	}

	// 向后合并，和向前合并一样
	while (true)
	{
		PAGE_ID nextId = span->_pageNum + span->_pageId;
		Span* nextSpan = static_cast<Span*>(_idSpanMap.Get(nextId));
		if (nextSpan == nullptr)
		{
			break;
		}

		//std::map<PAGE_ID, Span*>::iterator it = _idSpanMap.find(nextId);
		//// 如果没有找到
		//if (it == _idSpanMap.end())
		//{
		//	break;
		//}
		//Span* nextSpan = it->second;

		// 如果正在被使用
		if (nextSpan->_isUse == true)
		{
			break;
		}

		// 如果超过了128页
		if (nextSpan->_pageNum + span->_pageNum > static_cast<size_t>(NPAGES )- 1)
		{
			break;
		}

		// 没有问题，直接合并
		span->_pageNum += nextSpan->_pageNum;
		_spanLists[span->_pageNum].Erase(nextSpan);
		// delete nextSpan;
		_spanPool.Delete(nextSpan);
	}

	_spanLists[span->_pageNum].PushFront(span);
	span->_isUse = false;
	//_idSpanMap[span->_pageId] = span;
	//_idSpanMap[span->_pageId + span->_pageNum - 1] = span;
	_idSpanMap.Set(span->_pageId, span);
	_idSpanMap.Set(span->_pageId + span->_pageNum - 1, span);
}

Span* PageCache::NewSpan(PAGE_ID pageNum)
{
	assert(pageNum > 0);
	// 如果pageNum > NPAGES - 1
	size_t size = pageNum << PAGE_SHIFT;
	if (pageNum > NPAGES - 1)
	{
		// 直接向堆申请
		void* ptr = SystemAlloc(pageNum);
		Span* span = _spanPool.New();
		// Span* span = new Span;
		span->_pageId = (PAGE_ID)ptr >> PAGE_SHIFT;
		span->_pageNum = pageNum;
		//_idSpanMap[span->_pageId] = span;
		_idSpanMap.Set(span->_pageId, span);

		return span;
	}

	if (!_spanLists[pageNum].Empty())
	{
		Span* kSpan = _spanLists[pageNum].PopFront();
		for (PAGE_ID i = 0; i < kSpan->_pageNum; ++i)
		{
			//_idSpanMap[kSpan->_pageId + i] = kSpan;
			_idSpanMap.Set(kSpan->_pageId + i, kSpan);
		}

		return kSpan;
	}

	// 没有span了，需要将更大的span切割成较小的span
	for (size_t i = pageNum + 1; i < NPAGES; ++i)
	{
		// 找到了大块的span
		if (!_spanLists[i].Empty())
		{
			// 开始分割
			// 直接获得一个span
			Span* nSpan = _spanLists[i].PopFront();
			// 新的span
			Span* kSpan = _spanPool.New();
			// Span* kSpan = new Span;
			kSpan->_pageId = nSpan->_pageId;
			kSpan->_pageNum = pageNum;

			nSpan->_pageId += pageNum;
			nSpan->_pageNum -= pageNum;
			_spanLists[nSpan->_pageNum].PushFront(nSpan);

			// 在_idSpanMap中插入nSpan
			//_idSpanMap[nSpan->_pageId] = nSpan;
			//_idSpanMap[nSpan->_pageId + nSpan->_pageNum - 1] = nSpan;
			_idSpanMap.Set(nSpan->_pageId, nSpan);
			_idSpanMap.Set(nSpan->_pageId + nSpan->_pageNum - 1, nSpan);

			for (PAGE_ID i = 0; i < kSpan->_pageNum; ++i)
			{
				_idSpanMap.Set(kSpan->_pageId + i, kSpan);
				//_idSpanMap[kSpan->_pageId + i] = kSpan;
			}

			return kSpan;
		}
	}

	// 走到这里，说明后面都没有大页的span了，那么我们需要去堆上申请
	Span* newSpan = _spanPool.New();
	// Span* newSpan = new Span;
	void* ptr = SystemAlloc(static_cast<PAGE_ID>(NPAGES) - 1);
	// 构造新申请的大页span(128页)
	newSpan->_pageId = ((PAGE_ID)ptr >> PAGE_SHIFT);
	newSpan->_pageNum = static_cast<PAGE_ID>(NPAGES) - 1;

	_spanLists[newSpan->_pageNum].PushFront(newSpan);

	// 申请到了大页的span，再次调用NewSpan
	return NewSpan(pageNum);
}